<?php


namespace App\Domain\Address\Services;


use App\Domain\Account\Dao\AccountDao;
use App\Domain\Address\Dao\AddressDao;
use App\Domain\Address\Models\VillageModel;
use App\Exceptions\ServiceException;
use App\Domain\Address\Models\AddressModel;
use App\Supports\Formatter\ResponseFormatter;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Storage;
use Illuminate\Database\Eloquent\Builder;

class AddressService
{
    /****************** 区划树处理 ********************/
    public $maxCacheLevel = 3;
    public $fileFormat;

    public function __construct()
    {
        $this->fileFormat = config('app.address_file_format');
    }

    /**
     * 缓存区划及其下级
     * 注：执行时间长
     * 只缓存到第三级（区）,支持全国cacheTree(0,0)
     * @param $regionId
     * @param $level
     */
    public function cacheAddress($regionId, $level)
    {
        ini_set('memory_limit', '-1');
        if ($regionId == '0') {
            $tree = $this->getSons(0, 0);
            $this->setCache(0, $tree);
            foreach ($tree as $childTree) {
                $this->cacheTree($childTree);
            }
        } else {
            $tree = $this->getAddressTree($regionId, $level);
            $this->cacheTree($tree);
        }
    }

    /**
     * 获取区划树
     * @param $regionId
     * @param $level
     * @return mixed
     */
    public function getAddress($regionId, $level)
    {
        if ($level <= 3) {
            return json_decode($this->getCache($regionId));
        } else {
            return $this->getAddressTree($regionId, $level);
        }
    }

    /**
     * 当前区划和下一级区划
     * @param $regionId
     * @param $level
     * @param $childrenLvl
     * @return mixed
     */
    public function getAddressSon($regionId, $level, $childrenLvl)
    {
        return $this->getAddressTree($regionId, $level, $childrenLvl);
    }


    /**
     * 递归缓存数据 注：执行时间长
     * @param $tree
     */
    protected function cacheTree($tree)
    {
        $this->setCache($tree['id'], $tree);
        if ($tree['level'] < $this->maxCacheLevel) {
            foreach ($tree['children'] as $childTree) {
                $this->cacheTree($childTree);
            }
        }
    }

    /**
     * 设置缓存
     * @param $regionId
     * @param $addressData
     */
    protected function setCache($regionId, $addressData)
    {
        Storage::put(sprintf($this->fileFormat, $regionId), json_encode($addressData));
    }

    /**
     * 获取缓存
     * @param $regionId
     * @return mixed
     */
    protected function getCache($regionId)
    {
        return Storage::get(sprintf($this->fileFormat, $regionId));
    }

    /**
     * 获取区划和下级树
     * @param $regionId
     * @param $level
     * @return mixed
     */
    public function getAddressTree($regionId, $level, $childrenLvl = -1)
    {
        if ($level <= 5) {
            $addr = AddressModel::query()->where('code', $regionId)->where('level_dict_code', $level)
                ->where('status', 1)->first();
            $data['id'] = $addr['code'];
            $data['label'] = $addr['name'];
            $data['status'] = $addr['state'];
            $data['level'] = $addr['level_dict_code'];
            $data['children'] = $this->getSons($addr['code'], $addr['level_dict_code'], $childrenLvl);
        } else {
            $addr = VillageModel::query()->where('uid', $regionId)
                ->where('status', 1)->first();
            $data['id'] = $addr['uid'];
            $data['label'] = $addr['name'];
            $data['status'] = $addr['state'];
            $data['level'] = '5';
            $data['children'] = [];
        }
        return $data;
    }

    /**
     * 递归获取下级树
     * @param $regionId
     * @param $level
     * @param $childrenLvl
     * @return array
     */
    public function getSons($regionId, $level, $childrenLvl = -1)
    {
        if ($childrenLvl == 0) {
            return [];
        }
        $childrenLvl--;
        $sons = [];
        if ($level < 5) {
            $list = AddressModel::query()->where('parent_code', $regionId)->where('level_dict_code', $level + 1)
                ->where('status', 1)->get();
            foreach ($list as $item) {
                $son['id'] = $item['code'];
                $son['label'] = $item['name'];
                $son['status'] = $item['state'];
                $son['level'] = $item['level_dict_code'];
                $son['children'] = $this->getSons($son['id'], $son['level'], $childrenLvl);
                $sons[] = $son;
            }
        }
        return $sons;
    }

    /**
     * @param $regionId
     * @param $level
     * @return AddressModel[]|\Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection
     */
    public function getBrother($regionId, $level)
    {
        if ($level < 5) {
            $address = AddressModel::query()->where('code', $regionId)->where('level_dict_code', $level)->where('status', 1)->first();
            if ($address == null) {
                throw new ServiceException('区划不存在');
            }
            return $this->getAddressSon($address->parent_code, $level - 1, 1);
        }
    }

    /****************** 区划树处理 ********************/

    public function parentTree($regionId, $level)
    {
        return $this->getParents($regionId, $level);
    }

    protected function getParents($regionId, $level, $children = [])
    {
        $thisData = [];
        $parentCode = 0;
        if ($level == 5) {
            $model = VillageModel::query()->where('uid', $regionId)
                ->where('status', 1)->first();
            $thisData['id'] = $model['uid'];
            $thisData['label'] = $model['name'];
            $thisData['level'] = '5';
            $parentCode = $model['town_code'];
        } else {
            $model = AddressModel::query()->where('code', $regionId)
                ->where('status', 1)->first();
            $thisData['id'] = $model['code'];
            $thisData['label'] = $model['name'];
            $thisData['level'] = $model['level_dict_code'];
            $parentCode = $model['parent_code'];
        }
        if (!empty($children)) {
            $thisData['children'] = $children;
        }
        if ($thisData['level'] > 1) {
            $data = $this->getParents($parentCode, $thisData['level'] - 1, $thisData);
        } else {
            $data = $thisData;
        }
        return $data;
    }

    public function province()
    {
        $address = AddressModel::query()->where('level_dict_code', '1')->where('status', 1)->get(['code', 'name', 'level_dict_code']);
        return $address;
    }


    public function setAddress($param)
    {
        $addressDao = new AddressDao();
        if ($param['code']) {

            $data = $addressDao->findByCode($param['code']);
            $level = $addressDao->findByParentCode($param['parent_code']);
            if ($data) {
                $res = [
                    'name' => $param['name'],
                    'parent_code' => $param['parent_code'],
                    'level_dict_code' => $level['level_dict_code'] + 1,
                ];
                $data = $addressDao->update($data, $res);
            }
        } else {
            $level = $addressDao->findByParentCode($param['parent_code']);
            $data = $addressDao->create([
                'name' => $param['name'],
                'parent_code' => $param['parent_code'],
                'level_dict_code' => $level['level_dict_code'] + 1,
            ]);
        }
        return $data;

    }

    public function del($id)
    {
        $addressDao = new AddressDao();
        $data = $addressDao->del($id);
        return $data;
    }

    /**
     * 区划列表
     * @param $param
     * @return LengthAwarePaginator|Builder[]|Collection
     */
    public function list($param)
    {
        $query = AddressModel::query()
            ->select('address.*')
            ->where('address.status', 1);
        $query = $query->where(function (Builder $query) use ($param) {
            if (isset($param['regionId']))
                $query->where('parent_code', $param['regionId'])
                    ->where('status', 1)->first();
        });
        if (isset($param['pageSize']) && isset($param['currentPage'])) {
            return $query->paginate($param['pageSize'], ['*'], 'page', $param['currentPage']);
        } else {
            return $query->get();
        }
    }

    /**
     * 递归获取下级树
     * @param $regionId
     * @param $level
     * @param $childrenLvl
     * @return array
     */
    public function getListSons($regionId, $level, $childrenLvl = -1)
    {
        if ($childrenLvl == 0) {
            return [];
        }
        $sons = [];
        $childrenLvl--;
        if ($level < 5) {
            $list = AddressModel::query()->where('parent_code', $regionId)->where('level_dict_code', $level + 1)
                ->where('status', 1)->get();
            foreach ($list as $item) {
                $son['id'] = $item['code'];
                $son['label'] = $item['name'];
                $son['status'] = $item['state'];
                $son['level'] = $item['level_dict_code'];
                $son['children'] = $this->getSons($son['id'], $son['level'], $childrenLvl);
                $sons[] = $son;
            }
        }
        return $sons;
    }
}
